/*
 * Copyright (c) 2025, 大连理工大学 (Dalian University of Technology)
 *
 * Licensed under the Mulan PSL v2.
 * You can use this file according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of the License at
 *
 *     http://license.coscl.org.cn/MulanPSL2
 *
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. SEE THE MULAN PSL v2
 * FOR MORE DETAILS.
 */

#pragma once

#include "DBManager/Repository/HDF5/Base/MainlyRepositoryBase.h"

SG_DBMANAGER_HDF5_NAMESPACE_OPEN

template <typename T>

class DBManager_DECLSPEC SingleRepositoryBase : public MainlyRepositoryBase<T>
{
  public:
    explicit SingleRepositoryBase (HDF5Database& database) : MainlyRepositoryBase<T> (database) {};

    ~SingleRepositoryBase () {};

    std::vector<T>* LoadReadCache (std::size_t loadIndex) override
    {
        auto& mainCache       = this->GetMainCache ();
        auto&  mainDatasetInfo = this->GetMainDatasetInfo ();

        std::size_t beginIndex = 0;
        std::size_t length     = 0;
        mainDatasetInfo.CalcIndexBeginAndLength (loadIndex, _OUT beginIndex, _OUT length, this->GetDatasetCacheSize ());

        auto* cacheVec = this->m_cacheHelper.template GetVectorFast<T> (mainCache.m_readCacheKey);
        if (!cacheVec)
        {
            cacheVec = new std::vector<T>;
            cacheVec->reserve (length);
            this->GetDataset (mainDatasetInfo.GetPath ()).select ({ beginIndex }, { length }).read (*cacheVec);
            this->m_cacheHelper.template CacheVector (mainCache.m_readCacheKey, cacheVec);
        }
        else
        {
            this->GetDataset (mainDatasetInfo.GetPath ()).select ({ beginIndex }, { length }).read (*cacheVec);
            // 更新该key在缓存池占用内存大小
            this->GetDatabase ().GetCachePool ().UpdateMemorySize (mainCache.m_readCacheKey, cacheVec->size () * sizeof (T));
        }
        mainCache.dataMinIndex = beginIndex;
        mainCache.dataMaxIndex = beginIndex + length;
        return cacheVec;
    }

    // 转存数据
    void DumpWriteCahce () override
    {
        std::vector<T>& writeStorage = this->GetMainCache ().m_writeStorage;
        // 如果缓存区没有数据，直接返回
        if (writeStorage.empty ())
        {
            return;
        }
        // 1. 将主表的顺序标记设为 false，表示数据可能不是顺序存储的
        this->GetMainDatasetInfo ().SetIsSequential (false);

        // 2. 将缓存区中的数据追加到主表中
        this->WriteData (this->GetMainDatasetInfo (), writeStorage);

        // 3. 更新Index表
        this->WriteIndexData (this->GetIndexDatasetInfo (), writeStorage);

        // 4. 清空缓存区的数据
        writeStorage.clear ();
    }

    /**
     * @brief 纯虚函数，用于对数据进行排序，需由派生类实现。
     *
     * @return 排序是否成功
     */
    void SortData () override
    {
        if (!this->GetMainCache ().m_writeStorage.empty ())
        {
            this->DumpWriteCahce ();
        }

        if (this->GetMainDatasetInfo ().IsSequential () || !this->GetMainDatasetInfo ().IsCreate ())
        {
            return;
        }

        auto mainDataset = this->GetDataset (this->GetMainDatasetInfo ().GetPath ());

        std::vector<T> datas;

        mainDataset.read (datas);

        // 对数据进行排序
        std::sort (datas.begin (), datas.end ());

        mainDataset.select ({ 0 }, { datas.size () }).write (datas);

        this->RewriteIndexData (datas);

        // 设置为已顺序
        this->GetMainDatasetInfo ().SetIsSequential (true);
    }

    /**
     * @brief    Get the All Data object
     *
     * @return
     * @author   wxc
     * @date     2024.12.25
     */
    std::vector<T> GetAllData () override
    {
        this->Sort ();

        std::vector<T> list;

        if (this->GetMainDatasetInfo ().IsCreate ())
        {
            this->GetDataset (this->GetMainDatasetInfo ()).read (list);  ///< 读取所有数据
        }

        return list;
    }
};

SG_DBMANAGER_HDF5_NAMESPACE_CLOSE
